#include "board.h"
#include "step.h"
#include<QPainter>
#include<QMouseEvent>
#include<QDebug>
#include<QMessageBox>
#include<QPushButton>
#include<QMenuBar>
#include<QVector>



board::board(QWidget *parent) :
    QWidget(parent)
{
    for(int i=0;i<32;++i){
        _s[i].init(i);
    }
    _selectid=-1;
    _bredturn=true;
    gameover=false;

    setWindowTitle("对弈");//窗口名字
    setFixedSize(650,500);//设置固定窗口大小

    //创建对弈说明按钮
    QPushButton *btn1=new QPushButton;
    btn1->setParent(this);
    btn1->setText("对弈说明");//显示文本
    btn1->resize(90,35);//设置按钮大小
    btn1->move(470,35);//移动按钮
    connect(btn1,&QPushButton::clicked,this,&board::printshuoming);

    //创建行棋一方按钮
    QPushButton *btn2=new QPushButton;
    btn2->setParent(this);
    btn2->setText("显示行棋方");//显示文本
    btn2->resize(90,35);//设置按钮大小
    btn2->move(470,85);//移动按钮
    connect(btn2,&QPushButton::clicked,this,&board::printxingqi);

    //创建悔棋按钮
    QPushButton *btn3=new QPushButton;
    btn3->setParent(this);
    btn3->setText("悔棋");//显示文本
    btn3->resize(90,35);//设置按钮大小
    btn3->move(470,135);//移动按钮
    connect(btn3,&QPushButton::clicked,this,&board::backstep);

    //重新开始按钮
    QPushButton *btn4=new QPushButton;
    btn4->setParent(this);
    btn4->setText("开始新棋局");//显示文本
    btn4->resize(90,35);//设置按钮大小
    btn4->move(470,185);//移动按钮
    connect(btn4,&QPushButton::clicked,this,&board::relivestone);

}


//绘制当前棋盘状况的核心函数，需要实时更新即update();才能调用
//所有的绘制都在paintEvent
void board::paintEvent(QPaintEvent *)
{
    QPainter painter(this);

    //背景
    QPixmap pix;
    pix.load(":/image/woodboard.jpg");
    painter.drawPixmap(0,0,this->width(),this->height(),pix);

    //棋盘绘制
    drawbasicboard(painter);
    writechuhan(painter);
    //行棋一方
    if(prxingqi){
        writexingqi(painter);
    }
    //如果游戏结束
    if(gameover==true){
        writewin(painter);
    }

    //绘制棋子
    for(int i=0;i<32;++i){
        drawstone(painter,i);
    }

}


//写楚河汉界
void board::writechuhan(QPainter&painter){
    //写下楚河汉界
    painter.setFont(QFont("隶书",_r,700));
    painter.setPen(Qt::black);
    QRectF rect1(80,200,40,40);
    painter.drawText(rect1,"楚",QTextOption(Qt::AlignCenter));
    QRectF rect2(120,200,40,40);
    painter.drawText(rect2,"河",QTextOption(Qt::AlignCenter));
    QRectF rect3(240,200,40,40);
    painter.drawText(rect3,"漢",QTextOption(Qt::AlignCenter));
    QRectF rect4(280,200,40,40);
    painter.drawText(rect4,"界",QTextOption(Qt::AlignCenter));
}
//画基本棋盘
void board::drawbasicboard(QPainter&painter){
    int d = 40;
    _r=d/2;

    QRectF rectwai(10,10,380,420);

    //外框
    painter.setPen(Qt::black);
    painter.drawRect(rectwai);


    // 画10横线
    for(int i=1; i<=10; ++i)
    {
        painter.drawLine(QPoint(d, i*d), QPoint(9*d, i*d));
    }
    // 画9竖线
    for(int i=1; i<=9; ++i)
    {
        if(i==1 || i==9)
            painter.drawLine(QPoint(i*d, d), QPoint(i*d, 10*d));
        else
        {
            painter.drawLine(QPoint(i*d, d), QPoint(i*d, 5*d));
            painter.drawLine(QPoint(i*d, 6*d), QPoint(i*d, 10*d));
        }
    }

    // 九宫格
    painter.drawLine(QPoint(4*d, 1*d), QPoint(6*d, 3*d));
    painter.drawLine(QPoint(6*d, 1*d), QPoint(4*d, 3*d));

    painter.drawLine(QPoint(4*d, 8*d), QPoint(6*d, 10*d));
    painter.drawLine(QPoint(6*d, 8*d), QPoint(4*d, 10*d));
}
//写出行棋一方
void board::writexingqi(QPainter &painter){
    QRectF rect(120,440,160,40);
    painter.setFont(QFont("华文楷体",_r,700));
    if(_bredturn){
        painter.setPen(Qt::red);
        painter.drawText(rect,"红方行棋",QTextOption(Qt::AlignCenter));
        update();
    }else{
        painter.setPen(Qt::black);
        painter.drawText(rect,"黑方行棋",QTextOption(Qt::AlignCenter));
        update();
    }
}
//写出胜负结果
void board::writewin(QPainter &painter){
    //QRectF rect5(400,180,160,40);
    QRectF rect6(440,250,160,40);
    painter.setPen(Qt::black);
    painter.setFont(QFont("华文楷体",_r,700));
    //painter.drawText(rect5,"胜负已定",QTextOption(Qt::AlignCenter));
    for(int m=0;m<32;m++){
        if(_s[m]._type==stone::jiang&&_s[m]._dead==true&&m<16){
            painter.drawText(rect6,"黑方胜利",QTextOption(Qt::AlignCenter));
            break;
        }
        else if(_s[m]._type==stone::jiang&&_s[m]._dead==true&&m>=16&&m<32){
            painter.drawText(rect6,"红方胜利",QTextOption(Qt::AlignCenter));
            break;
        }
    }
}
//出现对弈说明弹窗
void board::printshuoming(){
    QMessageBox qme;
    qme.setText("【1】红方先走，以吃掉对方的将/帅为胜。\n"
                "【2】为便于教学演示，支持连续多步悔棋。\n"
                "【3】行棋规则简述如下：\n"
                "帅（将）：只能在“九宫”之内活动，可上可下，可左可右，每次走动只能按竖线或横线走动一格。\n"
                "仕（士）：只能在九宫内走动，行棋路径只能是九宫内的斜线。士一次只能走一个斜格。\n"
                "兵（卒）：只能向前走，不能后退，在未过河前，不能横走。过河以后还可左右移动，一次一步。\n"
                "象（相）：每次循对角线走两格，活动范围限于“河界”以内的本方阵地，如果它走的“田”字中央有一个棋子，就不能走。\n"
                "车：无论横线、竖线均可行走，只要无子阻拦，步数不受限制。\n"
                "炮：在不吃子时，走动与车完全相同，在吃子时必须跳过一个棋子，自方的和敌方的均可。\n"
                "马：走动的方法是一直一斜，即先横着或直着走一格，然后再斜着走一个对角线，如果在要去的方向有别的棋子挡住，马就无法走过去，俗称“蹩马腿”。\n");
    qme.exec();
    return;
}


//将普通的行和列转换成像素点，返回棋子所在的坐标，返回类型为指针
QPoint board::center(int row,int col){
    QPoint ret;
    ret.rx()=(col+1)*_r*2;
    ret.ry()=(row+1)*_r*2;
    return ret;
}
QPoint board::center(int id){
    return center(_s[id]._row,_s[id]._col);
}


//绘制指定的单个棋子
void board::drawstone(QPainter& painter,int id){
//如果棋子已被吃
    if(_s[id]._dead==true)
        return;
//返回棋子圆心坐标的指针
    QPoint c=center(id);
//确定写名字的地方
    QRect rect=QRect(c.x()-_r,c.y()-_r,_r*2,_r*2);

//如果正在绘制的棋子被选定，就标灰，否则为白
    if(id==_selectid){
        painter.setBrush(QBrush(Qt::gray));
    }else{//表现为没有被选定的棋子是白底
        painter.setBrush(QBrush(Qt::white));
    }
//边框与文字颜色设定
    if(_s[id]._red){
        painter.setPen(Qt::red);}
    else{
        painter.setPen(Qt::black);}
//设置字体
    painter.setFont(QFont("隶书",_r,700));

//根据已经得到的圆心坐标画圆
    painter.drawEllipse(center(id),_r,_r);
//写名字
    if(id<16){
        painter.drawText(rect,_s[id].getText(),QTextOption(Qt::AlignCenter));
    }else{
        painter.drawText(rect,_s[id].getText(),QTextOption(Qt::AlignCenter));
    }

}


//所点击的位置
bool board::getrowcol(QPoint pt,int &row,int &col){
    for(row=0;row<=9;row++){
        for(col=0;col<=8;col++){
            QPoint c=center(row,col);//返回圆心坐标的指针
            int dx=c.x()-pt.x();
            int dy=c.y()-pt.y();
            int dist=dx*dx+dy*dy;
            if(dist<_r*_r){
                return true;
            }
        }
    }return false;
}


//判断某个位置上是否有棋子并得到id
int board::getid(int row, int col)
{
    for(int i=0; i<32; ++i)
    {
        if(_s[i]._row == row && _s[i]._col == col && !_s[i]._dead)
            return i;
    }
    return -1;
}


//返回两个点之间的棋子个数
int board::getstonecount(int row1,int col1,int row2,int col2)
{
    int count=0;
    if(row1!=row2&&col1!=col2){
        return -1;
    }//不在同一条线上，不合要求
    if(row1==row2&&col1==col2){
        return -1;
    }//同一个点，不合要求

    if(row1==row2){
        int min=col1<col2 ? col1 : col2;//返回较小值
        int max=col1<col2 ? col2 : col1;//返回较大值
        for(int col=min+1;col<max;++col){
            if(getid(row1,col)!=-1){++count;}
        }
    }
    else{
        int min=row1<row2 ? row1 : row2;//返回较小值
        int max=row1<row2 ? row2 : row1;//返回较大值
        for(int row=min+1;row<max;++row){
            if(getid(row,col1)!=-1){++count;}
        }
    }

    return count;
}


//将的移动
bool board::canmovejiang(int moveid,int row,int col,int){
    //只能在九宫内移动，一次一格
    if(_s[moveid]._red){
        if(row>2)return false;
    }
    else{
        if(row<7)return false;
    }
    if(col<3)return false;
    if(col>5)return false;

    int dr=_s[moveid]._row-row;//distance of row
    int dc=_s[moveid]._col-col;//distance of col
    int d=abs(dr)*10+abs(dc);//表示原位置与目标位置的关系
    if(d==1||d==10){return true;}
    return false;
}
//仕的移动
bool board::canmoveshi(int moveid,int row,int col,int){
    if(_s[moveid]._red){
        if(row>2)return false;
    }
    else{
        if(row<7)return false;
    }
    if(col<3)return false;
    if(col>5)return false;
    int dr=_s[moveid]._row-row;
    int dc=_s[moveid]._col-col;
    int d=abs(dr)*10+abs(dc);
    if(d==11){return true;}
    return false;
}
//象的移动
bool board::canmovexiang(int moveid,int row,int col,int){
    int row1 = _s[moveid]._row;
    int col1 = _s[moveid]._col;
    int move=abs(row1-row)*10+abs(col1-col);
    if(move!=22){
        return false;
    }
    //不能过河
    if(_s[moveid]._red&&row>4){
        return false;
    }else if(!_s[moveid]._red&&row<5){
        return false;
    }
    //象眼的判断
    int reye=(row+row1)/2;
    int ceye=(col+col1)/2;
    if(getid(reye,ceye)!=-1){
        return false;
    }
    return true;
}
//车的移动
bool board::canmoveche(int moveid,int row,int col,int){
    int row1 = _s[moveid]._row;
    int col1 = _s[moveid]._col;
    int count=getstonecount(row1,col1,row,col);
    if(count==0){return true;}
    return false;
}
//马的移动
bool board::canmovema(int moveid,int row,int col,int){
    int row1 = _s[moveid]._row;
    int col1 = _s[moveid]._col;
    int move=(qAbs(row1-row))*10+qAbs(col1-col);
    //行棋没有成日字
    if((move!=12)&&(move!=21)){return false;}
    //蹩马腿
    if(move==12){
        if(getid(row1,(col+col1)/2)!=-1){return false;}
    }
    else if(move==21){
        if(getid((row+row1)/2,col1)!=-1){return false;}
    }
    return true;
}
//炮的移动
bool board::canmovepao(int moveid,int row,int col,int killid){
    int row1 = _s[moveid]._row;
    int col1 = _s[moveid]._col;
    int count=getstonecount(row1,col1,row,col);
    if(killid!=-1){
        if(count==1){return true;}//吃子
    }
    else{
        if(count==0){return true;}//仅移动
    }
    return false;
}
//兵的移动
bool board::canmovebing(int moveid,int row,int col,int){
    int row1 = _s[moveid]._row;
    int col1 = _s[moveid]._col;
    int move=(qAbs(row1-row))*10+qAbs(col1-col);
    if(_s[moveid]._red&&row<row1){return false;}
    if(!_s[moveid]._red&&row>row1){return false;}
    //move为1意为横着走，move为10意为竖着走
    //未过河
    if(_s[moveid]._red&&_s[moveid]._row<=4){
        if(move!=10){return false;}
    }else if(!_s[moveid]._red&&_s[moveid]._row>=5){
        if(move!=10){return false;}
    }
    //已过河
    else if(_s[moveid]._red&&_s[moveid]._row>=5){
        if(move!=1&&move!=10){return false;}
    }else if(!_s[moveid]._red&&_s[moveid]._row<=4){
        if(move!=1&&move!=10){return false;}
    }
    //if(move!=1&&move!=10){return false;}
    return true;
}
//判断是否符合走棋规则
bool board::canmove(int moveid,int row,int col,int killid){
    //目标棋子与移动的棋子阵营相同
    if(_s[moveid]._red==_s[killid]._red){
        _selectid=killid;
        update();
        return false;
    }
    //判断是哪一方行棋
    if((_bredturn&&!_s[moveid]._red)||(!_bredturn&&_s[moveid]._red)){
        return false;
    }
    //根据棋子名字选择走法
    switch(_s[moveid]._type){
    case stone::jiang:
        return canmovejiang(moveid,row,col,killid);
        break;
    case stone::shi:
        return canmoveshi(moveid,row,col,killid);
        break;
    case stone::xiang:
        return canmovexiang(moveid,row,col,killid);
        break;
    case stone::che:
        return canmoveche(moveid,row,col,killid);
        break;
    case stone::ma:
        return canmovema(moveid,row,col,killid);
        break;
    case stone::pao:
        return canmovepao(moveid,row,col,killid);
        break;
    case stone::bing:
        return canmovebing(moveid,row,col,killid);
        break;
    }
    return true;
}


//保存行棋过程
void board::savestep(int moveid,int killid,int row,int col,QVector<step*>& steps)
{
    step* step0=new step;
    step0->_precol=_s[moveid]._col;
    step0->_nowcol=col;
    step0->_prerow=_s[moveid]._row;
    step0->_nowrow=row;
    step0->_moveid=moveid;
    step0->_killid=killid;
    if(moveid<16){
        step0->_preredturn=true;
    }else{
        step0->_preredturn=false;
    }

    steps.append(step0);

}


//鼠标动作
void board::mouseReleaseEvent(QMouseEvent *ev){
    QPoint pt =ev->pos();//得到鼠标点击的位置
    int row,col;//鼠标点击的位置的行列号
    bool bret=getrowcol(pt,row,col);
    if(bret==false)return;//点到棋盘外
    int i;
    int clickid=-1;
    for(i=0;i<32;++i){
        if(_s[i]._row==row&&_s[i]._col==col&&_s[i]._dead==false){break;}
    }
    if(i<32){
        clickid=i;
    }

    if(_selectid==-1){//之前没有棋子被选中
        if(clickid!=-1){//现在选中了一枚棋子
            _selectid=clickid;
            update();
        }
    }
    else{
        if(canmove(_selectid,row,col,clickid)){
            savestep(_selectid,clickid,row,col,steps);//为悔棋功能保存行棋过程
            //允许行棋
            _s[_selectid]._row=row;
            _s[_selectid]._col=col;
            if(clickid!=-1){
                _s[clickid]._dead=true;
            }
            _selectid=-1;
            _bredturn=!_bredturn;
            update();
        }_selectid=-1;
    }

    //每次点击都查一下是不是已经把对方的将（帅）吃掉了，如果吃掉了就gameover=true;
    for(int k=0;k<32;++k){
        if(_s[k]._type==stone::jiang&&_s[k]._dead==true){
            gameover=true;
        }
    }
}


//悔棋
void board::backstep()
{
    //判断是否是第一步
    if(this->steps.size()==0){return;}
    //恢复棋子的所有状态
    step* step0=this->steps.last();

    //上一步操作将棋子移动到空白位置
    if(step0->_killid==-1)
    {
        //只要将moveId的行列修改就可以了
        _s[step0->_moveid]._row=step0->_prerow;
        _s[step0->_moveid]._col=step0->_precol;
        _bredturn=step0->_preredturn;
        update();
    }
    else
    {
        //需要将killId棋子状态恢复，将moveId棋子状态恢复
        _s[step0->_moveid]._row=step0->_prerow;
        _s[step0->_moveid]._col=step0->_precol;
        _s[step0->_killid]._dead=false;
        _s[step0->_killid]._row=step0->_nowrow;
        _s[step0->_killid]._col=step0->_precol;
        _bredturn=step0->_preredturn;
        update();
    }
    steps.removeLast();
    delete step0;
}


//恢复初始状态
void board::relivestone(){
    for(int t=0;t<32;t++){
        _s[t]._dead=false;
    }
    resetstone();
    gameover=false;
    _bredturn=true;
    _selectid=-1;
    update();
    return;
}
//重置棋子位置
void board::resetstone(){
    //红方
    int cshi1=0;
    int cxiang1=0;
    int cma1=0;
    int cche1=0;
    int cpao1=0;
    int cbing1=0;
    for(int x=0;x<16;++x){
        if(_s[x]._type==stone::jiang){//jiang
            _s[x]._row=0;_s[x]._col=4;
        }
        else if(_s[x]._type==stone::shi){//shi
            cshi1++;
            if(cshi1==1){_s[x]._row=0;_s[x]._col=3;}
            else{_s[x]._row=0;_s[x]._col=5;}
        }
        else if(_s[x]._type==stone::xiang){//xiang
            cxiang1++;
            if(cxiang1==1){_s[x]._row=0;_s[x]._col=2;}
            else{_s[x]._row=0;_s[x]._col=6;}
        }
        else if(_s[x]._type==stone::ma){//ma
            cma1++;
            if(cma1==1){_s[x]._row=0;_s[x]._col=1;}
            else{_s[x]._row=0;_s[x]._col=7;}
        }
        else if(_s[x]._type==stone::che){//che
            cche1++;
            if(cche1==1){_s[x]._row=0;_s[x]._col=0;}
            else{_s[x]._row=0;_s[x]._col=8;}
        }
        else if(_s[x]._type==stone::pao){//pao
            cpao1++;
            if(cpao1==1){_s[x]._row=2;_s[x]._col=1;}
            else{_s[x]._row=2;_s[x]._col=7;}
        }
        else if(_s[x]._type==stone::bing){//bing
            cbing1++;
            _s[x]._row=3;
            _s[x]._col=2*(cbing1-1);
        }
    }
    //黑方
    int cshi2=0;
    int cxiang2=0;
    int cma2=0;
    int cche2=0;
    int cpao2=0;
    int cbing2=0;
    for(int y=16;y<32;++y){
        if(_s[y]._type==stone::jiang){//jiang
            _s[y]._row=9;_s[y]._col=4;
        }
        else if(_s[y]._type==stone::shi){//shi
            cshi2++;
            if(cshi2==1){_s[y]._row=9;_s[y]._col=3;}
            else{_s[y]._row=9;_s[y]._col=5;}
        }
        else if(_s[y]._type==stone::xiang){//xiang
            cxiang2++;
            if(cxiang2==1){_s[y]._row=9;_s[y]._col=2;}
            else{_s[y]._row=9;_s[y]._col=6;}
        }
        else if(_s[y]._type==stone::ma){//ma
            cma2++;
            if(cma2==1){_s[y]._row=9;_s[y]._col=1;}
            else{_s[y]._row=9;_s[y]._col=7;}
        }
        else if(_s[y]._type==stone::che){//che
            cche2++;
            if(cche2==1){_s[y]._row=9;_s[y]._col=0;}
            else{_s[y]._row=9;_s[y]._col=8;}
        }
        else if(_s[y]._type==stone::pao){//pao
            cpao2++;
            if(cpao2==1){_s[y]._row=7;_s[y]._col=1;}
            else{_s[y]._row=7;_s[y]._col=7;}
        }
        else if(_s[y]._type==stone::bing){//bing
            cbing2++;
            _s[y]._row=6;
            _s[y]._col=2*(cbing2-1);
        }
    }
    update();
}


